﻿#pragma once

#include "Misc/EngineEditorMacros.h"
#include "Object/Object.h"
#include "MaterialGraph/MaterialGraphValueType.h"
#include "Math/Vec4.h"
#include "MaterialGraphPinModel.m.h"

class RMaterialGraphLinkModel;
class RMaterialGraphNodeModel;

RCLASS(ExtraHeader = "MaterialGraph/Link/MaterialGraphLinkModel.h")
class RMaterialGraphPinModel : public RObject
{
    ROBJECT

public:
    RFIELD()
    EMaterialGraphValueType ValueType;

    //is input pin or output pin
    RFIELD()
    bool bIsOutput = false;

    //default value for input pin
    //will be used when no connection
    //if value type is Vector1D,just use X
    //if value type is Vector2D,just use X,Y
    //if value type is Vector3D,use X,Y,Z
    //if value type is Vector4D,use X,Y,Z,W
    RFIELD()
    float DefaultInputX=0.f;
    RFIELD()
    float DefaultInputY=0.f;
    RFIELD()
    float DefaultInputZ=0.f;
    RFIELD()
    float DefaultInputW=0.f;
    

    //获取最后一个连接
    //对于输入引脚，只有最后的连接有效
    TSharedObjectPtr<RMaterialGraphLinkModel> GetLastLink() const
    {
        if (Links.Empty())
        {
            return nullptr;
        }
        return Links.Last();
    }
protected:

    //当前引脚的连接
    //输入和输出引脚都可以有多个连接
    //对于输入引脚，只有最后的连接有效
    RFIELD()
    TVector<TSharedObjectPtr<RMaterialGraphLinkModel>> Links;

public:
    TDelegate<void> OnLinkChanged;

    void AddLink(TSharedObjectPtr<RMaterialGraphLinkModel> InLink)
    {
        Links.Add(InLink);
        OnLinkChanged.ExecuteIfBound();
    }

    void RemoveLink(TSharedObjectPtr<RMaterialGraphLinkModel> InLink)
    {
        Links.Remove(InLink);
        OnLinkChanged.ExecuteIfBound();
    }

    const TVector<TSharedObjectPtr<RMaterialGraphLinkModel>>& GetLinks()
    {
        return Links;
    }

    //这个引脚是否隐藏
    //输入和输出引脚都可以隐藏
    //要注意的是，
    //假设有连接L连接到输出引脚O1和输入引脚I1
    //①隐藏输出引脚O1
    //②创建新的连接L2连接到输出引脚O2和输入引脚I1
    //③显示输出引脚O1
    //这时，输入引脚I1就有两个连接，这是不允许的
    //为了避免这种情况，输入引脚允许有多个连接，但只有最后一个连接有效
    RFIELD()
    bool bIsHidden = false;

    //get value expression in shader
    //only valid or input pin
    CString GetValueExpression() const;

    bool HasValidLink() const;
    TSharedObjectPtr<RMaterialGraphLinkModel> GetFirstValidLink() const;

    TSharedObjectPtr<RMaterialGraphNodeModel> GetNode() const;

    //the unique name of the linked ouput pin
    //will be assigned when create shader code
    CString UniqueOutputPinName;
};